package qqserver.service;

import qqcommon.Message;
import qqcommon.MessageType;
import qqcommon.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author DCSGO
 * @version 1.0
 * 服务端
 * 用户登录
 */
public class QQServer {
    //HashMap的升级版 支持多线程 是线程安全的
    private static final ConcurrentHashMap<String, User> validUsers = new ConcurrentHashMap<>();

    static {//静态代码块 初始化 validUsers
        User u1 = new User("DCSGO", "8888");
        User u2 = new User("徐小明", "1234");
        User u3 = new User("王强", "1111");
        User u4 = new User("Tom", "2222");
        User u5 = new User("Java", "3333");
        validUsers.put(u1.getUserId(), u1);
        validUsers.put(u2.getUserId(), u2);
        validUsers.put(u3.getUserId(), u3);
        validUsers.put(u4.getUserId(), u4);
        validUsers.put(u5.getUserId(), u5);

        SendMessageToOfflineService.addOfflineUser(u1.getUserId());
        SendMessageToOfflineService.addOfflineUser(u2.getUserId());
        SendMessageToOfflineService.addOfflineUser(u3.getUserId());
        SendMessageToOfflineService.addOfflineUser(u4.getUserId());
        SendMessageToOfflineService.addOfflineUser(u5.getUserId());
    }

    public boolean checkUser(String id, String pwd) {
        User user = validUsers.get(id);
        if (user == null) {//没有该用户 id
            return false;
        }
        if (!user.getPasswd().equals(pwd)) {//密码不匹配
            return false;
        }
        //是否已经登录 只允许一个账号一个用户登录
        return ManageServerConnectClientThreads.get(id) == null;
    }

    public QQServer() {
        ServerSocket serverSocket = null;
        try {
            System.out.println("等待用户登录...");
            serverSocket = new ServerSocket(9999);
            new Thread(new SendToAllService()).start();
            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("有用户连接！");
                ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
                Message message = new Message();

                //读取主机发送的 user 对象
                ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
                User user = (User) ois.readObject();
                if (checkUser(user.getUserId(), user.getPasswd())) {
                    //登录成功
                    //向主机发送登录成功的消息
                    message = new Message();
                    message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
                    oos.writeObject(message);
                    oos.flush();
                    /*
                    EOF异常就是执行了下面的代码
                    clientSocket.shutdownOutput();//表示服务器不会继续发送数据
                    此时客户端 socket.getInputStream() 就会抛出异常
                    */

                    //创建与该用户的连接
                    ServerConnectClientThread thread = new ServerConnectClientThread(user.getUserId(), clientSocket);
                    thread.start();
                    System.out.println("已和 " + user.getUserId() + " 建立连接，读取消息中...");
                    ManageServerConnectClientThreads.add(thread.getUserId(), thread);

                    if (SendMessageToOfflineService.isOfflineUser(user.getUserId())) {//该用户是离线后再上线的
                        SendMessageToOfflineService.sendMessages(user.getUserId(), clientSocket);
                        SendMessageToOfflineService.removeOfflineUser(user.getUserId());
                    }

                } else {
                    //登录失败
                    //向主机发送登录失败的消息
                    message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
                    oos.writeObject(message);
                    oos.flush();
                    /*
                    EOF异常就是执行了下面的代码
                    clientSocket.shutdownOutput();//表示服务器不会继续发送数据
                    此时客户端 socket.getInputStream() 就会抛出异常
                    */

                    clientSocket.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
